summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am/library_applet_storage.cpp
blob: 0412c215d59b2f67a1fbdefedcf769d3c961419e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/memory.h"

namespace Service::AM {

namespace {

Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
    R_UNLESS(offset >= 0, AM::ResultInvalidOffset);

    const size_t begin = offset;
    const size_t end = begin + size;

    R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
    R_SUCCEED();
}

class BufferLibraryAppletStorage final : public LibraryAppletStorage {
public:
    explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
    ~BufferLibraryAppletStorage() = default;

    Result Read(s64 offset, void* buffer, size_t size) override {
        R_TRY(ValidateOffset(offset, size, m_data.size()));

        std::memcpy(buffer, m_data.data() + offset, size);

        R_SUCCEED();
    }

    Result Write(s64 offset, const void* buffer, size_t size) override {
        R_TRY(ValidateOffset(offset, size, m_data.size()));

        std::memcpy(m_data.data() + offset, buffer, size);

        R_SUCCEED();
    }

    s64 GetSize() override {
        return m_data.size();
    }

    Kernel::KTransferMemory* GetHandle() override {
        return nullptr;
    }

private:
    std::vector<u8> m_data;
};

class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
public:
    explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
                                                Kernel::KTransferMemory* trmem, bool is_writable,
                                                s64 size)
        : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
        m_trmem->Open();
    }

    ~TransferMemoryLibraryAppletStorage() {
        m_trmem->Close();
        m_trmem = nullptr;
    }

    Result Read(s64 offset, void* buffer, size_t size) override {
        R_TRY(ValidateOffset(offset, size, m_size));

        m_memory.ReadBlock(m_trmem->GetSourceAddress() + offset, buffer, size);

        R_SUCCEED();
    }

    Result Write(s64 offset, const void* buffer, size_t size) override {
        R_UNLESS(m_is_writable, ResultUnknown);
        R_TRY(ValidateOffset(offset, size, m_size));

        m_memory.WriteBlock(m_trmem->GetSourceAddress() + offset, buffer, size);

        R_SUCCEED();
    }

    s64 GetSize() override {
        return m_size;
    }

    Kernel::KTransferMemory* GetHandle() override {
        return nullptr;
    }

protected:
    Core::Memory::Memory& m_memory;
    Kernel::KTransferMemory* m_trmem;
    bool m_is_writable;
    s64 m_size;
};

class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
public:
    explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
                                        Kernel::KTransferMemory* trmem, s64 size)
        : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
    ~HandleLibraryAppletStorage() = default;

    Kernel::KTransferMemory* GetHandle() override {
        return m_trmem;
    }
};

} // namespace

LibraryAppletStorage::~LibraryAppletStorage() = default;

std::vector<u8> LibraryAppletStorage::GetData() {
    std::vector<u8> data(this->GetSize());
    this->Read(0, data.data(), data.size());
    return data;
}

std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
    return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
}

std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
                                                                  Kernel::KTransferMemory* trmem,
                                                                  bool is_writable, s64 size) {
    return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
}

std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
                                                          Kernel::KTransferMemory* trmem,
                                                          s64 size) {
    return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
}

} // namespace Service::AM